home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1997 February / EnigmA AMIGA RUN 15 (1997)(G.R. Edizioni)(IT)[!][issue 1997-02][PLANET CD V].iso / enigma / earcd / sviluppo / svilupp2 / amphn192.lha / src / Sampler.c < prev    next >
C/C++ Source or Header  |  1996-11-16  |  9KB  |  300 lines

  1. /*
  2. **    Sampler.c, Copyright © 1995 by Olaf `Olsen' Barthel
  3. **        Placed in the Public Domain
  4. **
  5. **    :ts=4
  6. */
  7.  
  8. #include <hardware/dmabits.h>
  9. #include <hardware/intbits.h>
  10. #include <hardware/custom.h>
  11. #include <hardware/cia.h>
  12.  
  13. #include <devices/audio.h>
  14.  
  15. #include <resources/misc.h>
  16.  
  17. #include <dos/dosextens.h>
  18.  
  19. #include <exec/execbase.h>
  20. #include <exec/memory.h>
  21.  
  22. #include <clib/exec_protos.h>
  23. #include <clib/misc_protos.h>
  24. #include <clib/dos_protos.h>
  25. #include <clib/alib_protos.h>
  26.  
  27. #ifdef WE_EVEN_HAD_THESE_JAF
  28. #include <pragmas/exec_pragmas.h>
  29. #include <pragmas/misc_pragmas.h>
  30. #endif
  31.  
  32.     // We'll replace #defines with references to globals. This is
  33.     // to avoid certain compiler optimizations that may have
  34.     // side-effects
  35.  
  36. #ifdef custom
  37. #undef custom
  38. #endif    // custom
  39.  
  40. #ifdef ciaa
  41. #undef ciaa
  42. #endif    // ciaa
  43.  
  44. #ifdef ciab
  45. #undef ciab
  46. #endif    // ciab
  47.  
  48. extern __far volatile struct Custom    custom;
  49. extern __far volatile struct CIA    ciaa;
  50. extern __far volatile struct CIA    ciab;
  51.  
  52.     // Audio channel bits
  53.  
  54. #define LEFT0F  1
  55. #define RIGHT0F  2
  56. #define RIGHT1F  4
  57. #define LEFT1F  8
  58.  
  59.     // Handy shortcuts for the two bits that enable sampler  input
  60.     // from the left and the right channel
  61.  
  62. #define LEFT_CHANNEL    CIAF_PRTRPOUT
  63. #define RIGHT_CHANNEL    CIAF_PRTRSEL
  64.  
  65.     // Here is where you define the sample rate. The Amiga audio hardware
  66.     // currently won't go beyond 28000 samples per second, so 22050 samples
  67.     // per second are a nice round number. Please note that since this program
  68.     // does stereo sampling the effective sampling rate is halved, effectively
  69.     // yielding 11025 samples per second.
  70.  
  71. #define SAMPLING_RATE    22050
  72.  
  73. LONG __saveds
  74. Main(VOID)
  75. {
  76.     STATIC UBYTE ChannelData[] = { LEFT0F | RIGHT0F, LEFT0F | RIGHT1F, LEFT1F | RIGHT0F, LEFT1F | RIGHT1F };
  77.  
  78.     struct ExecBase        *SysBase;
  79.     struct DosLibrary    *DOSBase;
  80.     struct Library        *MiscBase;
  81.  
  82.     struct MsgPort        *AudioPort;
  83.     struct IOAudio        *AudioRequest;
  84.     WORD                 LeftChannel;
  85.     WORD                 RightChannel;
  86.     UWORD                 AudioInt;
  87.     UWORD                 AudioDMA;
  88.  
  89.     UWORD                 Sample,Value;
  90.     BOOL                 IntLeftWasEnabled,
  91.                          DMALeftWasEnabled,
  92.                          IntRightWasEnabled,
  93.                          DMARightWasEnabled;
  94.     BOOL                 IsLeft;
  95.  
  96.         // Set up the libraries
  97.  
  98.     SysBase = *(struct ExecBase **)4;
  99.  
  100.     if(DOSBase = (struct DosLibrary *)OpenLibrary("dos.library",37))
  101.     {
  102.             // Open the audio.device driver
  103.  
  104.         if(AudioPort = CreateMsgPort())
  105.         {
  106.             if(AudioRequest = (struct IOAudio *)CreateIORequest(AudioPort,sizeof(struct IOAudio)))
  107.             {
  108.                 AudioRequest -> ioa_Request . io_Message . mn_Node . ln_Pri    = 127;
  109.                 AudioRequest -> ioa_Data                                    = ChannelData;
  110.                 AudioRequest -> ioa_Length                                    = sizeof(ChannelData);
  111.  
  112.                 if(!OpenDevice(AUDIONAME,NULL,(struct IORequest *)AudioRequest,NULL))
  113.                 {
  114.                         // misc.resource controls the parallel port bits
  115.  
  116.                     if(MiscBase = (struct Library *)OpenResource(MISCNAME))
  117.                     {
  118.                         STRPTR User;
  119.  
  120.                         if(!(User = AllocMiscResource(MR_PARALLELPORT,__FILE__)))
  121.                         {
  122.                             if(!(User = AllocMiscResource(MR_PARALLELBITS,__FILE__)))
  123.                             {
  124.                                     // Now check which audio channels we could allocate
  125.  
  126.                                 if((ULONG)AudioRequest -> ioa_Request . io_Unit & LEFT0F)
  127.                                     LeftChannel = 0;
  128.                                 else
  129.                                     LeftChannel = 3;
  130.  
  131.                                 if((ULONG)AudioRequest -> ioa_Request . io_Unit & RIGHT0F)
  132.                                     RightChannel = 1;
  133.                                 else
  134.                                     RightChannel = 2;
  135.  
  136.                                     // Build the interrupt and dma masks
  137.  
  138.                                 AudioInt = (1L << (INTB_AUD0 + LeftChannel)) | (1L << (INTB_AUD0 + RightChannel));
  139.                                 AudioDMA = (1L << (DMAB_AUD0 + LeftChannel)) | (1L << (DMAB_AUD0 + RightChannel));
  140.  
  141.                                     // Save interrupt/dma enabled bits for later
  142.  
  143.                                 IntLeftWasEnabled = (custom . intenar & (1L << (INTB_AUD0 + LeftChannel))) ? TRUE : FALSE;
  144.                                 DMALeftWasEnabled = (custom . dmaconr & (1L << (DMAB_AUD0 + LeftChannel))) ? TRUE : FALSE;
  145.  
  146.                                 IntRightWasEnabled = (custom . intenar & (1L << (INTB_AUD0 + RightChannel))) ? TRUE : FALSE;
  147.                                 DMARightWasEnabled = (custom . dmaconr & (1L << (DMAB_AUD0 + RightChannel))) ? TRUE : FALSE;
  148.  
  149.                                     // Switch the data direction of the parallel port we will
  150.                                     // be reading the samples from to input.
  151.  
  152.                                 ciaa . ciaddrb = 0;
  153.  
  154.                                     // Switch the data direction of the port we will use to
  155.                                     // select the channel to read to output
  156.  
  157.                                 ciab . ciaddra |= LEFT_CHANNEL | RIGHT_CHANNEL;    // Enable output to sampler
  158.  
  159.                                     // We start reading from the left channel
  160.  
  161.                                 ciab . ciapra = (ciab . ciapra & ~RIGHT_CHANNEL) | LEFT_CHANNEL;
  162.  
  163.                                 IsLeft = TRUE;
  164.  
  165.                                     // Set up the two audio channels for output. The trick we
  166.                                     // will use will give us both accurate sample timing and
  167.                                     // audio output of the data we are sampling. It goes like
  168.                                     // this: we disable audio DMA and write the sample data
  169.                                     // `manually' into the DAC registers. As soon as the audio
  170.                                     // state machine is finished playing this single sample
  171.                                     // an interrupt will be triggered. Since interrupts are
  172.                                     // disabled we will have to poll the interrupt request
  173.                                     // register until the interrupt is set. The rate at which
  174.                                     // the audio hardware generates the interrupts is exactly
  175.                                     // our sampling rate (obviously) and provides the accurate
  176.                                     // monotonous timing we need to record the sampler ouput.
  177.  
  178.                                 custom . aud[LeftChannel] . ac_ptr = NULL;
  179.                                 custom . aud[LeftChannel] . ac_len = 1;        // One word at a time
  180.                                 custom . aud[LeftChannel] . ac_per = (SysBase -> ex_EClockFrequency * 5) / SAMPLING_RATE;
  181.                                 custom . aud[LeftChannel] . ac_vol = 64;    // Maximum volume
  182.  
  183.                                 custom . aud[RightChannel] . ac_ptr = NULL;
  184.                                 custom . aud[RightChannel] . ac_len = 1;        // One word at a time
  185.                                 custom . aud[RightChannel] . ac_per = (SysBase -> ex_EClockFrequency * 5) / SAMPLING_RATE;
  186.                                 custom . aud[RightChannel] . ac_vol = 64;    // Maximum volume
  187.  
  188.                                     // Turn audio DMA channels off
  189.  
  190.                                 custom . dmacon = AudioDMA;
  191.  
  192.                                     // Disable audio interrupts
  193.  
  194.                                 custom . intena = AudioInt;
  195.  
  196.                                     // Clear pending requests
  197.  
  198.                                 custom . intreq = AudioInt;
  199.  
  200.                                 custom . aud[LeftChannel] . ac_dat = 0;        // Trigger interrupt
  201.  
  202.                                     // The Disable() could be replaced with a Forbid() if one
  203.                                     // doesn't need high sampling accuracy. As it is, interrupts
  204.                                     // may temporarily steal the CPU and cause `pops' in the
  205.                                     // recorded input.
  206.  
  207.                                 Disable();
  208.  
  209.                                 do
  210.                                 {
  211.                                         // Wait for audio interrupt
  212.  
  213.                                     while(!(custom . intreqr & AudioInt));
  214.  
  215.                                         // Clear request
  216.  
  217.                                     custom . intreq = AudioInt;
  218.  
  219.                                         // Grab the sampler value; it will be in the range 0..255,
  220.                                         // but the audio hardware expects signed sample values in
  221.                                         // the range -128..127 so we'll use old trick to turn the
  222.                                         // sample into a signed two's complement value.
  223.  
  224.                                     Value = ciaa . ciaprb ^ 0x80;
  225.  
  226.                                         // The audio hardware operates on words, not on bytes,
  227.                                         // so we'll have to fake a word by composing it of the
  228.                                         // byte we read.
  229.  
  230.                                     Sample = (Value << 8) | Value;
  231.  
  232.                                         // Write the sample value and set up for next
  233.                                         // interrupt
  234.  
  235.                                     if(IsLeft)
  236.                                         custom . aud[LeftChannel] . ac_dat = Sample;
  237.                                     else
  238.                                         custom . aud[RightChannel] . ac_dat = Sample;
  239.  
  240.                                         // Toggle the channel.
  241.  
  242.                                     IsLeft            ^= TRUE;
  243.                                     ciab . ciapra    ^= LEFT_CHANNEL | RIGHT_CHANNEL;
  244.                                 }
  245.                                 while(ciaa . ciapra & CIAF_GAMEPORT0);    // Wait for mouse to be pressed
  246.  
  247.                                     // Wait for audio interrupt
  248.  
  249.                                 while(!(custom . intreqr & AudioInt));
  250.  
  251.                                     // Clear request
  252.  
  253.                                 custom . intreq = AudioInt;
  254.  
  255.                                 Enable();
  256.  
  257.                                     // Restore interrupt and dma bits
  258.  
  259.                                 if(IntLeftWasEnabled)
  260.                                     custom . intena = INTF_SETCLR | (1L << (INTB_AUD0 + LeftChannel));
  261.  
  262.                                 if(IntRightWasEnabled)
  263.                                     custom . intena = INTF_SETCLR | (1L << (INTB_AUD0 + RightChannel));
  264.  
  265.                                 if(DMALeftWasEnabled)
  266.                                     custom . dmacon = DMAF_SETCLR | (1L << (DMAB_AUD0 + LeftChannel));
  267.  
  268.                                 if(DMARightWasEnabled)
  269.                                     custom . dmacon = DMAF_SETCLR | (1L << (DMAB_AUD0 + RightChannel));
  270.  
  271.                                 FreeMiscResource(MR_PARALLELBITS);
  272.                             }
  273.                             else
  274.                                 Printf("Parallel bits are in use by %s\n",User);
  275.  
  276.                             FreeMiscResource(MR_PARALLELPORT);
  277.                         }
  278.                         else
  279.                             Printf("Parallel port is in use by %s\n",User);
  280.                     }
  281.                     else
  282.                         Printf("Couldn't open misc.resource\n");
  283.  
  284.                     CloseDevice((struct IORequest *)AudioRequest);
  285.                 }
  286.                 else
  287.                     Printf("Cannot open audio.device\n");
  288.  
  289.                 DeleteIORequest(AudioRequest);
  290.             }
  291.  
  292.             DeleteMsgPort(AudioPort);
  293.         }
  294.  
  295.         CloseLibrary(DOSBase);
  296.     }
  297.  
  298.     return(0);
  299. }
  300.